import UHFDriver
import re
import time
import binascii
import random
import sys

from pyrfid.DataProtocol.Driver.SessionManager import SessionManager
from pyrfid.DataProtocol.Exception.ExecutionCodeException.NoResponseFromTagException import NoResponseFromTagException
from pyrfid.DataProtocol.Exception.ExecutionCodeException.TagCommunicationErrorException import TagCommunicationErrorException
from pyrfid.DataProtocol.Exception.ExecutionCodeException.InvalidParameterException import InvalidParameterException
from pyrfid.DataProtocol.Exception.ExecutionCodeException.InterrogatorCommunicationErrorException import InterrogatorCommunicationErrorException

from pyrfid.Util.Util import Util
from pyrfid.DataProtocol.Driver.DriverInterface import DriverInterface

class JTEDriver(UHFDriver.UHFDriver):
    
    MAX_READ_PAGES = 16
    MAX_BLOCK_WRITE_ON_WORD = 8
    MAX_EXECUTION_TIME = 5
    MULTIPLE_WORD_ACCESS = bool()
    __sessionManager = object
    RANDOME_INTERRUPTION = random.randint(17, 30)
    ACCESS_COUNTER = 0
    
    def __init__(self, level, isMultipleWordAccess):
        super(JTEDriver, self).__init__(level, isMultipleWordAccess, self.MAX_EXECUTION_TIME)
        self.MULTIPLE_WORD_ACCESS = isMultipleWordAccess
    
    def _selectCommand(self, Target, Action, Mask, Pointer = 0 , MemBank = 1):
        print " - SELECT COMMAND EXECUTE"
        selectCommandParameter = self.__convertIntToBin(Target, 3)+self.__convertIntToBin(Action, 3)+self.__convertIntToBin(MemBank, 2)
        
        MaskHex = ""
        for index in range(0, len(Mask)/2):
            MaskHex = MaskHex+Util.convertHexToBinaryHex(Mask[index*2:(index*2)+2])
            
        execute = self._executeAccessCommand('\x50'+Util.convertIntToBinaryHex(3 + 1 + (len(Mask)/2) + 1 )+Util.convertIntToBinaryHex(int(selectCommandParameter, 2))+Util.convertIntToBinaryHex(Pointer, 4)+Util.convertIntToBinaryHex(len(Mask)/2*8)+MaskHex+'\x01')
        
        result = list() 
        result.append(True)
        result.append(execute)
        
        return result
    
    def _inventoryCommand(self, Sel = 0, Session= 2, Target=0 , Q = 0, RepCnt = 0 , ACKBlen = 0):
        print "START: EXECUTE INVENTORY COMMAND============================================================"
        
        QueryParBinary = "000"+self.__convertIntToBin(Sel, 2)+self.__convertIntToBin(Session, 2)+self.__convertIntToBin(Target)        
        print "OPEN FIRST COMMAND"
        execute = self._executeAccessCommand('\x40\x07\x43'+Util.convertIntToBinaryHex(int(QueryParBinary, 2))+Util.convertIntToBinaryHex(Q, 2)+Util.convertIntToBinaryHex(RepCnt, 4)+Util.convertIntToBinaryHex(ACKBlen, 4))
        
        createTime = time.clock()
        handleValue = execute[14:18]
        UIILength = int(execute[18:20], 16) - 2
        
        PC = execute[20:24]
        UII = execute[24:24+(UIILength*4)]
        AFI = PC[2:]
        print "END: EXECUTE INVENTORY COMMAND============================================================"        
        return (handleValue, createTime, AFI, UII)
    
    def __getCheckByteBinary(self, command):
        """for use air command"""
        intValue = int(Util.calculateXOR(command), 16)
        return re.sub('0x', '', hex(intValue-1))
    
    def __convertIntToBin(self, intValue, minLength = 2):
        restValue = intValue % 2
        templateValue = intValue / 2
        resultBinary = str(restValue)
        
        while templateValue != 0 :
            restValue = templateValue % 2
            templateValue = templateValue / 2        
            resultBinary = str(restValue) + resultBinary
            
        if minLength != 0:
            resultBinary = resultBinary.zfill(minLength)
        return resultBinary
        
    def _executeCommand(self, command):
        check_byte = self.__getCheckByteBinary(command)
        
        writeCommand = ""
        if len(check_byte) == 1:
            writeCommand = command + binascii.unhexlify('0'+check_byte)
        else:
            if check_byte == '-1':
                check_byte = 'FF'
            writeCommand = command + binascii.unhexlify(check_byte)
            
        print "command is :::::::::::::::::::::::::::::::::: ser.write(\'",binascii.b2a_hex(writeCommand),"\')"
        response = ""
        
        ####################################################################
        # START
        ####################################################################
        startLocalTime = time.clock()
        self.ACCESS_COUNTER = self.ACCESS_COUNTER + 1
        self._ser.write(writeCommand)
        
        # if self.ACCESS_COUNTER == self.RANDOME_INTERRUPTION:
        #     print "=============================================================="
        #     print self.RANDOME_INTERRUPTION
        #     print "=============================================================="
        #     sys.exit()
        
        #get Response
        while response == "":
            response = self._ser.read(self._ser.inWaiting())            
            if time.clock() - startLocalTime >= 7:
                print response
                print "TIME OUT"
                raise NoResponseFromTagException

        # print binascii.b2a_hex(response)
        # print response
        ####################################################################
        # END
        ####################################################################
        executeTime = time.clock() - startLocalTime
        # print "TIME is ", executeTime
        # self.EXECUTE_TIME += executeTime

        #Executed Command Error Handle
        if binascii.b2a_hex(response[0]) != '00':
            if binascii.b2a_hex(response[0]) == '10':
                #raise "Invalid command (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            elif binascii.b2a_hex(response[0]) == '11':
                #raise "Invalid data format (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            elif binascii.b2a_hex(response[0]) == '12':
                #raise "Value out of range (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            elif binascii.b2a_hex(response[0]) == '13':
                #raise "Checkbyte error (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            elif binascii.b2a_hex(response[0]) == '20':
                #raise "Command timeout (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            elif binascii.b2a_hex(response[0]) == '30':
                #raise "Standby mode (Error Code is "+binascii.b2a_hex(response)+")"
                raise InvalidParameterException
            else:
                raise "Module Error (Error Code is "+binascii.b2a_hex(response)+")"
        
        return binascii.b2a_hex(response).upper()
    
    ##
    #
    #For Write*, Read*.. etc Access Command
    #Execute Error Handle
    #
    #@param command: 
    #
    ##
    def _executeAccessCommand(self, command):

        execute = self._executeCommand(command)
        
        #SUCCESS
        if execute[4:6] == '00':
            return execute

        print execute
        #Error Handle
        errorCommand = execute[4]
        ##print "error Code",errorCommand
        handleErrorCommand = "Error Command :"

        #original Code
        if errorCommand == '1':
            handleErrorCommand += "Select"
        elif errorCommand == '2':
            handleErrorCommand += "Query"
        elif errorCommand == '4':
            handleErrorCommand += "Query Rep"
        elif errorCommand == '5':
            handleErrorCommand += "ACK"
        elif errorCommand == '6':
            handleErrorCommand += "NAK"           
        elif errorCommand == '7':
            handleErrorCommand += "Req_RN"
        elif errorCommand == '8':
            handleErrorCommand += "second of Req_RN"
        elif errorCommand == '9':
            handleErrorCommand += "9Read , Write, Kill, Lock, BlockWrite, BlockErase, ReadLock, Access, Write Multiple Words, Block Lock, Block Read Lock , Get System Information, Set Attenuate Command "
        elif errorCommand == 'A':
            handleErrorCommand += "second of Kill, Access, Block Lock, Block Read Lock, Set Attenuate Command "
        elif errorCommand == 'F':
            handleErrorCommand += "fRead , Write, Kill, Lock, BlockWrite, BlockErase, ReadLock, Access, Write Multiple Words, Block Lock, Block Read Lock , Get System Information, Set Attenuate Command "
        elif errorCommand == 'A':
            handleErrorCommand += "Free Format"

        errorCode = execute[5]
        #print 'handleErrorCommand',handleErrorCommand
#To Do
        handleErrorCode = " handle Error :"
        if errorCode == '1':
            handleErrorCode += "1:Receive Time out"
            raise InterrogatorCommunicationErrorException
        elif errorCode == '3':
            handleErrorCode += "3:Receive data is too long"
        elif errorCode == '4':
            handleErrorCode += "4:CRC-16 is not agreement"
        elif errorCode == '5':
            handleErrorCode += "5:send handle value is not match receive handle value"
        elif errorCode == '6':
            handleErrorCode += "6:on write / block write / write multiple words ,  is not match of write Value , read Value"           
        elif errorCode == '7':
            handleErrorCode += "7:NAK"           
        elif errorCode == '8':
            handleErrorCode += "8:Memory Over"
            raise InvalidParameterException
        elif errorCode == '9':
            handleErrorCode += "9:Memory is Locked"
        elif errorCode == 'A':
            handleErrorCode += "a:magnetic field shortage"
            print handleErrorCode
            raise InterrogatorCommunicationErrorException
        elif errorCode == 'B':
            handleErrorCode += "b:etc Error"
        elif errorCode == 'C':
            handleErrorCode += "c:other Error"
        elif errorCode == 'D':
            handleErrorCode += "d:RW is Turn Off Status"
            print handleErrorCode
            raise InterrogatorCommunicationErrorException
        elif errorCode == 'E':
            handleErrorCode += "e:RW is over run time"
            print handleErrorCode
            raise InterrogatorCommunicationErrorException
        elif errorCode == 'F':
            handleErrorCode += "Free Format"
        print "error Code",errorCode
        print handleErrorCommand, handleErrorCode
        raise TagCommunicationErrorException
    
    def _turnOn(self):
        result = self._executeCommand('\x11\x03\x05\x3F\xFF')
    
    def _turnOff(self):
        result = self._executeCommand('\x12\x00')
    
    def _blockWriteCommand(self, tagId, executeBankType, startOnWordAddress, writeData):
        verify = 1
        option = '000'+str(verify)+'00'+self.__convertIntToBin(executeBankType, 2)
        count = 0
        
        while range(writeData/self.MAX_BLOCK_WRITE):
            
            executeWriteData = writeData[count*self.MAX_BLOCK_WRITE_ON_WORD*4:(count+1)*self.MAX_BLOCK_WRITE_ON_WORD*4]
            
            if executeWriteData == '1F84':
                print "error----------------"
                raise "ERROR"
                
            executeWriteStartAddress = startOnWordAddress + (count * self.MAX_BLOCK_WRITE_ON_WORD)
            execute = self._executeAccessCommand('\x5C'+ 
                Util.convertIntToBinaryHex( 1 + 2 + len(executeWriteData)/2  )+ 
                Util.convertIntToBinaryHex(int(option, 2)) + 
                Util.convertIntToBinaryHex( len(executeWriteData)/4 , 4)+ 
                Util.convertIntToBinaryHex( executeWriteStartAddress )+ 
                binascii.unhexlify(executeWriteData) + 
                Util.convertHexToBinaryHex(self.getSessionManager().getSession(tagId)))
            count += 1;
        
        if writeData % self.MAX_BLOCK_WRITE_ON_WORD == 0:
            return True
        
        executeWriteData = writeData[count*self.MAX_BLOCK_WRITE_ON_WORD*4:]
        executeWriteStartAddress = startOnWordAddress + (count * self.MAX_BLOCK_WRITE_ON_WORD)
        execute = self._executeAccessCommand('\x5C'+ 
            Util.convertIntToBinaryHex( 1 + 2 + len(executeWriteData)/2  )+ 
            Util.convertIntToBinaryHex(int(option, 2)) + 
            Util.convertIntToBinaryHex( len(executeWriteData)/4 , 4)+ 
            Util.convertIntToBinaryHex( executeWriteStartAddress )+ 
            binascii.unhexlify(executeWriteData) + 
            Util.convertHexToBinaryHex(self.getSessionManager().getSession(tagId)))
        
    
    def _writeMutipleCommand(self, tagId, executeBankType, startOnWordAddress, writeData):
        print "writeMutileCommand"
        verify = 1
        option = '000'+str(verify)+'00'+self.__convertIntToBin(executeBankType, 2)
        #resulte = self._executeAccessCommand('\x71'+Util.convertIntToBinaryHex( (executeWriteCountByWord * 2) + 6)+Util.convertIntToBinaryHex(writeBankType)+'\x00'+Util.convertIntToBinaryHex( executeWriteAddressOfWord )+Util.convertIntToBinaryHex( executeWriteCountByWord )+executeWriteData+Util.convertIntToBinaryHex(handleValue, 4))
    
    def _writeCommand(self, tagId, executeBankType, startOnWordAddress, writeData):
        print "writeCommand "
        verify = 1
        option = '000'+str(verify)+'00'+self.__convertIntToBin(executeBankType, 2)
        execute = self._executeAccessCommand('\x58\x07'+Util.convertIntToBinaryHex(int(option, 2))+Util.convertIntToBinaryHex(startOnWordAddress, 4)+binascii.unhexlify(writeData)+Util.convertHexToBinaryHex(self.getSessionManager().getSession(tagId)))
        
    def _readCommand(self, tagId, executeBankType, startOnWordAddress, Length):
        print "readCommand", startOnWordAddress, Length
        reply = self._executeAccessCommand('\x57\x06'+Util.convertIntToBinaryHex(executeBankType)+Util.convertIntToBinaryHex(startOnWordAddress, 4)+Util.convertIntToBinaryHex(Length)+Util.convertHexToBinaryHex(self.getSessionManager().getSession(tagId)))        
        return reply[6:len(reply)-2]
